package com.irdstudio.efp.esb.api.rest.psd.credit;

import com.alibaba.fastjson.JSONObject;
import com.irdstudio.basic.framework.core.constant.BaseConstant;
import com.irdstudio.basic.framework.core.constant.EsbRetCodeStandard;
import com.irdstudio.basic.framework.core.constant.SDicToLocalConstant;
import com.irdstudio.basic.framework.core.exception.BizException;
import com.irdstudio.basic.framework.core.exception.ESBException;
import com.irdstudio.basic.framework.core.threadpool.ApplicationThreadPool2;
import com.irdstudio.basic.framework.core.util.TimeUtil;
import com.irdstudio.basic.framework.core.util.UUIDUtil;
import com.irdstudio.basic.framework.core.util.sdic.SDicToLocal;
import com.irdstudio.basic.framework.core.vo.BaseInfo;
import com.irdstudio.basic.framework.core.vo.RetMsgVO;
import com.irdstudio.efp.console.common.ConsoleEnums;
import com.irdstudio.efp.console.common.psd.PsdConstantSet;
import com.irdstudio.efp.console.service.facade.PrdInfoService;
import com.irdstudio.efp.console.service.facade.PubSysInfoService;
import com.irdstudio.efp.console.service.facade.SCfgParamService;
import com.irdstudio.efp.console.service.vo.PrdInfoVO;
import com.irdstudio.efp.console.service.vo.SCfgParamVO;
import com.irdstudio.efp.cus.service.facade.CusWhiteListTecService;
import com.irdstudio.efp.cus.service.vo.CusWhiteListTecVO;
import com.irdstudio.efp.esb.api.bean.psd.credit.req.PsdCreditApplyReqBean;
import com.irdstudio.efp.esb.api.bean.psd.credit.resp.PsdCreditApplyRespBean;
import com.irdstudio.efp.esb.api.common.GroupeInterface;
import com.irdstudio.efp.esb.api.rest.EsbController;
import com.irdstudio.efp.esb.api.service.common.repository.PrdRepository;
import com.irdstudio.efp.esb.api.service.esb.EsbRespServcie;
import com.irdstudio.efp.esb.common.constant.ESBClientConstance;
import com.irdstudio.efp.esb.common.constant.EsbBizEnums;
import com.irdstudio.efp.esb.common.constant.MsLoanConstant;
import com.irdstudio.efp.esb.common.server.req.EsbReqServiceBean;
import com.irdstudio.efp.esb.common.server.resp.EsbRespServiceBean;
import com.irdstudio.efp.esb.service.bo.req.psd.PsdCreditApprReqBean;
import com.irdstudio.efp.esb.service.bo.req.psd.PsdSxQryRptsInfArryReq;
import com.irdstudio.efp.esb.service.bo.resp.psd.PsdCreditApprRespBean;
import com.irdstudio.efp.esb.service.facade.EsbInvokeWrapper;
import com.irdstudio.efp.esb.service.facade.psd.PsdCreditApprService;
import com.irdstudio.efp.limit.service.facade.LmtPrdContService;
import com.irdstudio.efp.limit.service.vo.LmtPrdContVO;
import com.irdstudio.efp.loan.service.facade.AccLoanService;
import com.irdstudio.efp.loan.service.vo.AccLoanVO;
import com.irdstudio.efp.nls.common.constant.NlsApplyInfoEnums;
import com.irdstudio.efp.nls.common.constant.QueueTaskEnums;
import com.irdstudio.efp.nls.service.facade.NlsApplyInfoService;
import com.irdstudio.efp.nls.service.facade.NlsQueueSoltComnService;
import com.irdstudio.efp.nls.service.facade.psd.*;
import com.irdstudio.efp.nls.service.facade.queue.NlsProcessBizService;
import com.irdstudio.efp.nls.service.facade.sx.NlsCreditInfoService;
import com.irdstudio.efp.nls.service.vo.NlsApplyInfoVO;
import com.irdstudio.efp.nls.service.vo.psd.NlsApplyApprovalInfoVO;
import com.irdstudio.efp.nls.service.vo.psd.NlsCreditApprovalInfoVO;
import com.irdstudio.efp.nls.service.vo.psd.PreNlsCreditInfoVO;
import com.irdstudio.efp.nls.service.vo.queue.NlsProcessBizVO;
import com.irdstudio.efp.nls.service.vo.signature.SignatureRecordVO;
import com.irdstudio.efp.nls.service.vo.sx.NlsCreditInfoVO;
import com.irdstudio.efp.rule.common.enumeration.RefuseType;
import jdk.nashorn.internal.ir.IfNode;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ddf.NullEscherSerializationListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.irdstudio.efp.console.common.ConsoleConstant.LIMIT_STS_02;

@RestController
@RequestMapping("/esb")
public class PsdCreditApplyController implements EsbController {

    /**
     * 日志信息
     */
    private final Logger logger = LoggerFactory.getLogger(PsdCreditApplyController.class);

    @Autowired
    private PreNlsCreditInfoService preNlsCreditInfoService;

    @Autowired
    private EsbRespServcie<PsdCreditApplyRespBean> esbRespServcie;

    @Autowired
    private NlsCreditApprovalInfoService nlsCreditApprovalInfoService;

    @Autowired
    private NlsCreditInfoService nlsCreditInfoService;

    @Autowired
    private NlsApplyInfoService nlsApplyInfoService;

    @Autowired
    private LmtPrdContService lmtPrdContService;

    @Autowired
    @Qualifier("nlsProcessBizService")
    private NlsProcessBizService nlsProcessBizService;

    @Autowired
    private PrdRepository prdRepository;

    @Autowired
    private PsdCreditApprService psdCreditApprService;

    @Autowired
    private NlsQueueSoltComnService nlsQueueSoltComnService;

    @Autowired
    private PsdSqsSignatureService sqsSignatureService;

    @Autowired
    @Qualifier("applicationThreadPool")
    private ApplicationThreadPool2 threadPool;

    @Autowired
    private AccLoanService accLoanService;

    @Autowired
    private QuotaCheckService quotaCheckService;

    @Autowired
    private PubSysInfoService pubSysInfoService;

    @Autowired
    private SCfgParamService sCfgParamService;

    @Autowired
    private CusWhiteListTecService cusWhiteListTecService;

    @Autowired
    @Qualifier("prdInfoService")
    private PrdInfoService prdInfoService;


    @PostMapping("/SERVICE_30220001_15")
    public EsbRespServiceBean doRecv(@Validated @ModelAttribute("esbReqServiceBean") EsbReqServiceBean esbReqServiceBean, BindingResult bindingResult1,
                                     @Validated({GroupeInterface.psd.class}) @ModelAttribute("psdCreditApplyReqBean") PsdCreditApplyReqBean psdCreditApplyReqBean, BindingResult bindingResult2, Exception exception) {
        final String glblSrlNo = esbReqServiceBean.getSysHead().getGlblSrlNo();
        logger.info("发起授信申请：" + JSONObject.toJSONString(psdCreditApplyReqBean) + "全局流水号" + glblSrlNo);
        // 设置系统头对象
        setSysHeadFieldThreadLocal(esbReqServiceBean);
        //返回信息
        PsdCreditApplyRespBean psdCreditApplyRespBean = new PsdCreditApplyRespBean();
        try {
            // 参数校验
            if (Objects.nonNull(exception)) {
                //如果异常不为空，那么处理异常返回信息
                return esbRespServcie.getEsbRespServiceBeanByException(
                        esbReqServiceBean,
                        exception,
                        psdCreditApplyRespBean,
                        EsbRetCodeStandard.JKYDCSJYBTG);
            }
            //判断产品信息是否存在并且有效
            PrdInfoVO product = prdRepository.getProduct(psdCreditApplyReqBean.getProdCd());
            // 1	待生效
            // 2	生效
            // 3	失效
            if (Objects.isNull(product) || !"2".equals(product.getPrdStatus())) {
                throw new BizException("产品信息不存在或者产品状态不为生效");
            }
//            //根据渠道申请号查询是否已经存在授信申请记录
//            final NlsCreditApprovalInfoVO nlsCreditApprovalInfoVO = nlsCreditApprovalInfoService.selectByChannelApplyNo(psdCreditApplyReqBean.getChannelApplyNo());
//            if (!Objects.isNull(nlsCreditApprovalInfoVO)) {
//                throw new BizException("已存在核额申请记录，无需再次发起");
//            }
            //判断全局流水号是否存在
            final NlsCreditInfoVO golbalSernoParam = new NlsCreditInfoVO();
            golbalSernoParam.setGlobalSerno(glblSrlNo);
            final List<NlsCreditInfoVO> nlsCreditInfoVOS = nlsCreditInfoService.selectByGlobalSerno(golbalSernoParam);
            if (nlsCreditInfoVOS != null && !nlsCreditInfoVOS.isEmpty()) {
                throw new BizException("已存在全局流水号为" + glblSrlNo + "的请求记录");
            }
            //根据授信申请号查询是否已经存在申请记录
            final NlsCreditInfoVO nlsCreditInfoVO = nlsCreditInfoService.queryByLmtApplySeq(psdCreditApplyReqBean.getCrdtAppFlowNo());
            if (!Objects.isNull(nlsCreditInfoVO)) {
                throw new BizException("已存在授信申请流水号为" + psdCreditApplyReqBean.getCrdtAppFlowNo() + "的授信申请记录");
            }
            //判断预授核额申请状态是否为通过
            PreNlsCreditInfoVO prdPkParam = new PreNlsCreditInfoVO();
            prdPkParam.setChannelApplyNo(psdCreditApplyReqBean.getChannelApplyNo());
            PreNlsCreditInfoVO preNlsCreditInfoVO = preNlsCreditInfoService.queryByChannelApplyNo(prdPkParam);
            if (Objects.isNull(preNlsCreditInfoVO)) {
                throw new BizException("查询到预核额信息为空");
            }
            if (!"02".equals(preNlsCreditInfoVO.getStatus())) {
                throw new BizException("预核额状态未通过，拒绝进行核额申请");
            }
            /*//判断审批时间距离现在是否超过
            final long until = LocalDateTime.parse(preNlsCreditInfoVO.getApprovalTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).until(LocalDateTime.now(), ChronoUnit.DAYS);
            if (until > 90) {
                throw new BizException("预核额审批时间已经超过三个月，拒绝进行核额申请");
            }*/
            //判断预授信信息中的企业名称是否不为空
            if (StringUtils.isEmpty(preNlsCreditInfoVO.getEnterpriseName())) {
                //throw new BizException("预核额信息中的企业名称为空");
                throw new BizException("尊敬的客户，您暂不符合我行普税贷办理条件。如有贷款需求，请联系我行网点服务人员办理，谢谢！");
            }
            //白名单试单判断
            checkCusWitch(preNlsCreditInfoVO);

            //判断客户是否存在处理中、暂停、挂起的申请记录 01：处理中 02：通过 03：拒绝 04：取消 05：挂起 06：审批作废
            //根据证件号查询授信申请记录
            NlsCreditInfoVO certCodeParam = new NlsCreditInfoVO();
            certCodeParam.setPrdCode(product.getPrdCode());
            certCodeParam.setPrdId(product.getPrdId());
            certCodeParam.setCertCode(preNlsCreditInfoVO.getCertNo());
            List<NlsCreditInfoVO> certCodeNlsCreditInfoVOS = nlsCreditInfoService.queryByCucCodeAndPrdId(certCodeParam);

            if (certCodeNlsCreditInfoVOS != null && !certCodeNlsCreditInfoVOS.isEmpty()) {
                for (NlsCreditInfoVO certCodeNlsCreditInfoVO : certCodeNlsCreditInfoVOS) {
                    if ("01".equals(certCodeNlsCreditInfoVO.getApprvSts())||"05".equals(certCodeNlsCreditInfoVO.getApprvSts())) {
                        throw new BizException("尊敬的客户，您在我行有信用、保证类贷款申请仍在审批中。请待审批结束后再试，谢谢！");
                    }
                    if ("02".equals(certCodeNlsCreditInfoVO.getApprvSts())) {
                        //throw new BizException("当前存在有效的授信申请记录");
                        throw new BizException("尊敬的客户，您暂不符合我行普税贷办理条件。如有贷款需求，请联系我行网点服务人员办理，谢谢！");
                    }
                }
            }
            //根据证件号查询最近一次风控审批通过或者拒绝的记录，三个月内拒绝申请
            NlsCreditApprovalInfoVO nlsCreditApprovalInfoVOS = nlsCreditApprovalInfoService.selectByChannelApplyNo(psdCreditApplyReqBean.getChannelApplyNo());
            if (!Objects.isNull(nlsCreditApprovalInfoVOS)) {
                    //判断时间是否未超过90天
                    long until = LocalDateTime.parse(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(nlsCreditApprovalInfoVOS.getApproveTime()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).until(LocalDateTime.now(), ChronoUnit.DAYS);
                    if (until <= 90) {
                        logger.error("全局流水号" + glblSrlNo + "根据证件号查询最近一次风控审批通过或者拒绝的记录，三个月内拒绝申请");
                        //throw new BizException("已经完成准入审批，三个月内拒绝申请，请三个月后再次发起");
                        throw new BizException("尊敬的客户，您暂不符合我行普税贷办理条件。如有贷款需求，请联系我行网点服务人员办理，谢谢！");
                    }
            }
            //根据证件号判断客户是否存在余额，存在的话则拒绝
            checkLoanBanlance1(preNlsCreditInfoVO);
            //checkLoanBanlance2(certCodeNlsCreditInfoVOS);
            //预防占用产品限额
            RetMsgVO retMsgVO = quotaCheckService.preOccupied(psdCreditApplyReqBean.getCrdtAppFlowNo(), preNlsCreditInfoVO.getReAmount());
            if (!retMsgVO.isRetFlag()) {
                throw new BizException("尊敬的客户，当前贷款产品的可用余额不足。如有贷款需求，请联系我行网点服务人员办理，谢谢！");
            }
            //往授信审批信息表、授信申请表、业务过程表插入数据。
            insertNlsCreditApprovalInfo(psdCreditApplyReqBean, preNlsCreditInfoVO, glblSrlNo);
            insertSqsRecord(psdCreditApplyReqBean);
            NlsCreditInfoVO nlsInsertRecord = insertNlsCreditInfo(psdCreditApplyReqBean, preNlsCreditInfoVO, product, glblSrlNo);
            composeProcessBizVoInfoInsert(psdCreditApplyReqBean, preNlsCreditInfoVO);
            //发起异步申请 发起大数据审批请求 先预留
            callFkSp(nlsInsertRecord, psdCreditApplyReqBean, preNlsCreditInfoVO, glblSrlNo);
            //返回报文
            return esbRespServcie.getSucessBean(esbReqServiceBean, psdCreditApplyRespBean, EsbRetCodeStandard.SUCCESS);
        } catch (BizException e) {
            logger.error("全局流水号" + glblSrlNo + "授信申请出现异常，异常信息为：" + e.getMessage());
            clearPreOccupied(psdCreditApplyReqBean);
            return esbRespServcie.getEsbRespServiceBeanByException(esbReqServiceBean, e, psdCreditApplyRespBean, EsbRetCodeStandard.YWLJCLYC);
        } catch (Exception ex) {
            logger.error("全局流水号" + glblSrlNo + "授信申请出现异常，异常信息为：" + ex.getMessage());
            clearPreOccupied(psdCreditApplyReqBean);
            return esbRespServcie.getEsbRespServiceBeanByException(esbReqServiceBean, ex, psdCreditApplyRespBean, EsbRetCodeStandard.OTHERS_EXCEPTION);
        }
    }

    private void checkCusWitch(PreNlsCreditInfoVO preNlsCreditInfoVO) throws Exception {
        /** 白名单试单 **/
        SCfgParamVO sCfgParamVO = new SCfgParamVO();
        sCfgParamVO.setParamKey(ConsoleEnums.ParamKey.PSD_TRIAL_ORDER_SWITCH.getValue());
        sCfgParamVO.setParamValue(BaseConstant.YES_Y);
        sCfgParamVO = sCfgParamService.queryByCondition(sCfgParamVO);
        if(Objects.nonNull(sCfgParamVO)) {
            CusWhiteListTecVO cusWhiteListTecVO = new CusWhiteListTecVO();
            //cusWhiteListTecVO.setCertType(preNlsCreditInfoVO.getCertType());
            //cusWhiteListTecVO.setCertNo(preNlsCreditInfoVO.getCertNo());
            cusWhiteListTecVO.setCusName(preNlsCreditInfoVO.getCertName());
            cusWhiteListTecVO.setPrdCode(preNlsCreditInfoVO.getPrdId());
            List<CusWhiteListTecVO> cusWhiteListTecVOS = cusWhiteListTecService.queryByPrdCodeAndCusName(cusWhiteListTecVO);
            if (cusWhiteListTecVOS == null || cusWhiteListTecVOS.isEmpty()) {
                throw new BizException("尊敬的客户您好，由于您不属于本产品的目标客户，所以拒绝本次申请。");
            }
        }
    }

    private void clearPreOccupied(PsdCreditApplyReqBean psdCreditApplyReqBean) {
        try {
            quotaCheckService.clearPreOccupied(psdCreditApplyReqBean.getCrdtAppFlowNo());
        } catch (Exception e) {
            logger.error("授信申请清除预占用额度发生异常" + e.getMessage());
        }
    }

    /**
     * 判断行内是否存在授信申请通过的信用类记录
     *
     * @param preNlsCreditInfoVO
     * @throws Exception
     */
    private void checkLoanBanlance1(PreNlsCreditInfoVO preNlsCreditInfoVO) throws Exception {
        //判断是否存在处理中、挂起的信用担保类授信申请，如果存在则拒绝
        NlsCreditInfoVO param = new NlsCreditInfoVO();
        param.setAssureMeansMain(BaseConstant.ASSURE_MEANS_00);
        param.setCertType(preNlsCreditInfoVO.getCertType());
        param.setCertCode(preNlsCreditInfoVO.getCertNo());
        List<NlsCreditInfoVO> nlsCreditInfoVOS = nlsCreditInfoService.queryAllByCondition(param);
        if (nlsCreditInfoVOS != null) {
            for (NlsCreditInfoVO nlsCreditInfoVO : nlsCreditInfoVOS) {
                if ("01".equals(nlsCreditInfoVO.getApprvSts())||"05".equals(nlsCreditInfoVO.getApprvSts())) {
                    throw new BizException("尊敬的客户，您在我行有信用、保证类贷款申请仍在审批中。请待审批结束后再试，谢谢！");
                }
            }
        }

        //查询信用类贷款产品
        List<PrdInfoVO> prdInfoVOS = prdInfoService.listByGuarWay(BaseConstant.ASSURE_MEANS_00);
        if (prdInfoVOS != null) {
            if (!prdInfoVOS.isEmpty()) {
                for (PrdInfoVO prdInfoVO : prdInfoVOS) {
                    //根据产品和证件号码查询贷款记录
                    //如果存在有效的信用类授信申请记录（包含其它产品）且仍有贷款余额，则拒绝
                    //查询信用类的授信申请记录
                    List<AccLoanVO> accLoanVOS = accLoanService.queryByCertCodeAndPrdId(preNlsCreditInfoVO.getCertNo(), prdInfoVO.getPrdId());
                    if (accLoanVOS != null && accLoanVOS.size() > 0) {
                        for (AccLoanVO accLoanVO : accLoanVOS) {
                            if (!Objects.isNull(accLoanVO.getLoanBalance())) {
                                if (accLoanVO.getLoanBalance().doubleValue()>0) {
                                    throw new Exception("您在我行名下所有信用、保证类贷款需均结清方可重新申请。");
                                }
                            }
                        }
                    }
                }


            }
        }
    }

    private void insertSqsRecord(PsdCreditApplyReqBean psdCreditApplyReqBean) {
        SignatureRecordVO signatureRecordVO = new SignatureRecordVO();
        signatureRecordVO.setId(UUIDUtil.getUUID());
        signatureRecordVO.setPrdId(PsdConstantSet.prdId);
        signatureRecordVO.setApplySeq(psdCreditApplyReqBean.getCrdtAppFlowNo());
        signatureRecordVO.setLinkType(1);
        signatureRecordVO.setPolFileType(PsdConstantSet.PSD_FILE_TYPE_03);
        signatureRecordVO.setRetryNum(0);
        signatureRecordVO.setCreateTime(new Date());
        signatureRecordVO.setLastUpdateTime(new Date());
        signatureRecordVO.setSiuSta(0);
        //脱敏数据
        SignatureRecordVO tmSignatureRecordVO = new SignatureRecordVO();
        tmSignatureRecordVO.setId(UUIDUtil.getUUID());
        tmSignatureRecordVO.setPrdId(PsdConstantSet.prdId);
        tmSignatureRecordVO.setApplySeq(psdCreditApplyReqBean.getCrdtAppFlowNo());
        tmSignatureRecordVO.setLinkType(2);
        tmSignatureRecordVO.setPolFileType(PsdConstantSet.PSD_FILE_TM_TYPE_03);
        tmSignatureRecordVO.setRetryNum(0);
        tmSignatureRecordVO.setCreateTime(new Date());
        tmSignatureRecordVO.setLastUpdateTime(new Date());
        tmSignatureRecordVO.setSiuSta(0);
        sqsSignatureService.insertRecord(signatureRecordVO);
        sqsSignatureService.insertRecord(tmSignatureRecordVO);
    }

    /**
     * 调用风控审批
     *
     * @param psdCreditApplyReqBean
     * @param preNlsCreditInfoVO
     * @return
     */
    private void callFkSp(NlsCreditInfoVO nlsCreditInfoVO, PsdCreditApplyReqBean psdCreditApplyReqBean, PreNlsCreditInfoVO preNlsCreditInfoVO, String glblSrlNo) {
        PsdSxQryRptsInfArryReq psdQryRptsInfArry = new PsdSxQryRptsInfArryReq();
        //申请编号
        psdQryRptsInfArry.setAppNo(psdCreditApplyReqBean.getCrdtAppFlowNo());
        psdQryRptsInfArry.setlPRprsIdentNo(preNlsCreditInfoVO.getCertNo());
        psdQryRptsInfArry.setlPMblNo(psdCreditApplyReqBean.getMblNo());
        psdQryRptsInfArry.setlPNm(preNlsCreditInfoVO.getCertName());
        psdQryRptsInfArry.setlPIdentTp(preNlsCreditInfoVO.getCertType());
        psdQryRptsInfArry.setTaxpyrIdntfNo(preNlsCreditInfoVO.getTaxIdentificationNumber());
        psdQryRptsInfArry.setEntpNm(preNlsCreditInfoVO.getEnterpriseName());
        psdQryRptsInfArry.setEntpLo(preNlsCreditInfoVO.getRegistration());
        psdQryRptsInfArry.setEntpUSCC(preNlsCreditInfoVO.getSocialCreditCode());
        psdQryRptsInfArry.setUsrID(ESBClientConstance.CnsmrSysNo);
        psdQryRptsInfArry.setDeptNo(preNlsCreditInfoVO.getNlsOperOrgid());
        psdQryRptsInfArry.setLoanAnulIntRt(preNlsCreditInfoVO.getReYRate());
        //申请人网贷及个贷已有授信额度:同一个证件号的所有信用担保类型的有效的授信额度之和
        LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
        lmtPrdContVO.setCertType(preNlsCreditInfoVO.getCertType());
        lmtPrdContVO.setCertCode(preNlsCreditInfoVO.getCertNo());
        lmtPrdContVO.setLmtStatus(LIMIT_STS_02);
        lmtPrdContVO.setAssureMeansMain(BaseConstant.ASSURE_MEANS_00);
        List<LmtPrdContVO> lmtPrdContVOS = lmtPrdContService.aplcOCMExstdCrLmt(lmtPrdContVO);
        BigDecimal approveAmtTotal = lmtPrdContVOS.stream().
                map(LmtPrdContVO::getLmtAmt).
                filter(Objects::nonNull).
                reduce(BigDecimal.ZERO, BigDecimal::add);
        psdQryRptsInfArry.setAplcOCMExstdCrLmt(approveAmtTotal);

        PsdCreditApprReqBean psdCreditApprReqBean = new PsdCreditApprReqBean();
        ArrayList<PsdSxQryRptsInfArryReq> psdQryRptsInfArries = new ArrayList<>();
        psdQryRptsInfArries.add(psdQryRptsInfArry);
        psdCreditApprReqBean.setQryRptsInfArry(psdQryRptsInfArries);
        psdCreditApprReqBean.setGolSeq(glblSrlNo);
        EsbInvokeWrapper esbInvokeWrapper = new EsbInvokeWrapper(psdCreditApprService, psdCreditApprReqBean, nlsQueueSoltComnService);
        threadPool.add(() -> {
            try {
                PsdCreditApprRespBean result = (PsdCreditApprRespBean) esbInvokeWrapper.invoke3Threes();
                if (Objects.isNull(result) || Objects.isNull(result.getQryRptsInfArry()) || result.getQryRptsInfArry().size() < 1 || !EsbBizEnums.RetCodeEnum.SUCCESS.VALUE.equals(result.getQryRptsInfArry().get(0).getRcvSt())) {
                    throw new RuntimeException("调用风控接口异常：" + result.getQryRptsInfArry().get(0).getRcvRsltInf());
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("授信申请-风控审批异常：" + e.getMessage());
                //修改授信审批状态
                nlsCreditInfoVO.setApprvSts("03");
                nlsCreditInfoVO.setRejectReason(e.getMessage());
                nlsCreditInfoVO.setRefuseCause(e.getMessage());
                nlsCreditInfoService.updateByPk(nlsCreditInfoVO);
                //清除预占用额度
                clearPreOccupied(psdCreditApplyReqBean);
            }
        });
    }

    /**
     * 插入授信申请信息
     *
     * @param reqBean
     * @param preInfo
     * @param product
     */
    private NlsCreditInfoVO insertNlsCreditInfo(PsdCreditApplyReqBean reqBean, PreNlsCreditInfoVO preInfo, PrdInfoVO product, String glblSrlNo) throws Exception {
        final NlsCreditInfoVO nlsCreditInfoVO = new NlsCreditInfoVO();
        ///** 授信申请流水号 */
        //private String lmtApplySeq;
        nlsCreditInfoVO.setLmtApplySeq(reqBean.getCrdtAppFlowNo());
        ///** 预授信流水号 */
        //private String preLmtApplySeq;
        nlsCreditInfoVO.setPreLmtApplySeq(preInfo.getApplySeq());
        ///** 客户名称 */
        //private String cusName;
        nlsCreditInfoVO.setCusName(preInfo.getCertName());
        ///** 证件类型 */
        //private String certType;
        nlsCreditInfoVO.setCertType(SDicToLocal.getLocalSysDicVal(SDicToLocalConstant.CERT_TYPE_SED, preInfo.getCertType()));
        ///** 证件号码 */
        //private String certCode;
        nlsCreditInfoVO.setCertCode(preInfo.getCertNo());
        ///** 证件地址 */
        //private String certAddr;
        nlsCreditInfoVO.setCertAddr(reqBean.getCertAddr());
        ///** 证件有效期 */
        //private String certEndDt; 如果是有长期的英文的话转成yyMMDD 20991231
        nlsCreditInfoVO.setCertEndDt(reqBean.getIdenEfftDt());
        ///** 性别 */
        //private String gender;
        ///** 国籍 */
        //private String national;
        nlsCreditInfoVO.setNational(reqBean.getNation());
        ///** 职业 */
        //private String profession;
        nlsCreditInfoVO.setProfession(reqBean.getCrrCd());
        ///** 联系地址 */
        //private String indivRsdAddr;
        nlsCreditInfoVO.setIndivRsdAddr(reqBean.getCtcAddr());
        ///** 额度类型 */
        //private String lmtType;
        ///** 是否循环 */
        //private String cyclicFlg;
        nlsCreditInfoVO.setCyclicFlg(product.getCyclicWay());
        ///** 产品id */
        //private String prdId;
        nlsCreditInfoVO.setPrdId(reqBean.getProdCd());
        ///** 产品代码 */
        //private String prdCode;
        nlsCreditInfoVO.setPrdCode(reqBean.getProdCd());
        ///** 产品名称 */
        //private String prdName;
        nlsCreditInfoVO.setPrdName(reqBean.getLoanProdNm());
        ///** 申请金额 */
        //private BigDecimal applyAmt;
        ///** 审批金额(元) */
        //private BigDecimal approveAmt;
        //nlsCreditInfoVO.setApproveAmt(preInfo.getReAmount());
        ///** 期限 */
        //private String applyTerm;
        nlsCreditInfoVO.setApplyTerm("12");
        ///** 批复期限 */
        //private String approveTerm;
        //nlsCreditInfoVO.setApproveTerm(reqBean.getLoanAplTrm());
        ///** 期限类型 */
        //private String termType;
        nlsCreditInfoVO.setTermType("M");
        ///** 申请执行年利率% */
        nlsCreditInfoVO.setApplyRateY(product.getLoanIntRate().divide(new BigDecimal("100")));
        ///** 批复执行年利率% */
        //private BigDecimal approveRateY;
        //nlsCreditInfoVO.setApproveRateY(preInfo.getReYRate());
        ///** 担保方式 */
        //private String assureMeansMain;
        nlsCreditInfoVO.setAssureMeansMain(transferAssureMeansMain(product.getGuarWay()));
        ///** 担保方式2 */
        //private String assureMeans2;
        ///** 担保方式3 */
        //private String assureMeans3;
        ///** 币种 */
        //private String currencyType;
        nlsCreditInfoVO.setCurrencyType(SDicToLocal.getLocalSysDicVal(SDicToLocalConstant.CURRENCY, reqBean.getTxnCurrCd()));
        ///** 还款方式 */
        //private String repaymentMode;
        nlsCreditInfoVO.setRepaymentMode(product.getRepayWay());
        ///** 还款日类型 */
        //private String repaymentDayType;
        nlsCreditInfoVO.setRepaymentDayType(product.getRepayDayType());
        ///** 还款日 */
        //private String repaymentDay;
        nlsCreditInfoVO.setRepaymentDay(product.getRepayDay());
        ///** 贷款用途 */
        //private String loanUseType;
        ///** 申请日期 */
        //private String applyDate;
        nlsCreditInfoVO.setApplyDate(pubSysInfoService.getOpenday(BaseConstant.SYS_ID_1001));
        ///** 渠道号 */
        //private String channelNo;
        nlsCreditInfoVO.setChannelNo(reqBean.getChanNo());
        ///** 创建人 */
        //private String createUser;
        nlsCreditInfoVO.setCreateUser(BaseConstant.ADMIN);
        ///** 创建时间 */
        //private String createTime;
        nlsCreditInfoVO.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        ///** 手机号 */
        //private String indivMobile;
        nlsCreditInfoVO.setIndivMobile(reqBean.getMblNo());
        ///** 民族 */
        //private String ethnic;
        nlsCreditInfoVO.setEthnic(reqBean.getEthnicCd());
        ///** 学历 */
        //private String edu;
        nlsCreditInfoVO.setEdu(reqBean.getEduCd());
        ///** 工作单位名称 */
        //private String wrkCorpNm;
        ///** 工作单位地址 */
        //private String wrkCorpAddr;
        ///** 婚姻状况 */
        //private String mrgSitu;
        nlsCreditInfoVO.setMrgSitu(reqBean.getMrgSitu());
        ///** 配偶姓名 */
        //private String spsNm;
        nlsCreditInfoVO.setSpsNm(reqBean.getSpsNm());
        ///** 职称 */
        //private String ttl;
        nlsCreditInfoVO.setTtl(reqBean.getTtlCd());
        ///** 全局流水号 */
        //private String globalSerno;
        ///** 银行卡号 放款卡号 */
        //private String recvAccount;
        nlsCreditInfoVO.setRecvAccount(reqBean.getBankCardNo());
        ///** 客户申办日期起 */
        //private String applyDateMin;
        ///** 客户申办日期止 */
        //private String applyDateMax;
        ///** 放款卡号 */
        //private String dnAccount;
        nlsCreditInfoVO.setDnAccount(reqBean.getDistrCardNo());
        ///** 单位电话*/
        //private String wrkCorpMobile;
        ///** 最高学位*/
        //private String indivDgr;
        ///** 住宅性质*/
        //private String addrNature;
        ///** 家庭邮编*/
        //private String postCode;
        ///** email*/
        //private String email;
        ///** 行业*/
        //private String indivComFld;
        ///** 职务*/
        //private String indivComJobTtl;

        //repaymentPeriod 还款周期
        nlsCreditInfoVO.setRepaymentPeriod("01");

        //repaymentPeriodType 还款周期单位;
        nlsCreditInfoVO.setRepaymentPeriodType("M");

        //判断预授信的推荐人工号是否为空
        ///** 网贷经办人 */
        //private String nlsOperUserid;
        nlsCreditInfoVO.setNlsOperUserid(preInfo.getNlsOperUserid());
        ///** 网贷经办机构 */
        //private String nlsOperOrgid;
        nlsCreditInfoVO.setNlsOperOrgid(preInfo.getNlsOperOrgid());
        //插槽阶段
        //nlsCreditInfoVO.setSoltStage(PrdAdaptedSoltEnums.PsdSoltStageEnum.CREDIT.getVALUE());
        nlsCreditInfoVO.setGlobalSerno(glblSrlNo);

        nlsCreditInfoVO.setApprvSts("01");

        final int insert = nlsCreditInfoService.insertNlsCreditInfo(nlsCreditInfoVO);
        if (insert != 1) {
            logger.error("普税贷授信申请 授信申请流水号:【" + reqBean.getCrdtAppFlowNo() + "】 插入授信信息表出现异常!");
            throw new ESBException(EsbRetCodeStandard.SJCLYC.getValue(), "插入数据入授信信息表出现异常!");
        }
        return nlsCreditInfoVO;
    }

    /**
     * 插入授信基本信息
     *
     * @param psdCreditApplyReqBean
     * @param preNlsCreditInfoVO
     */
    private void insertNlsCreditApprovalInfo(PsdCreditApplyReqBean psdCreditApplyReqBean, PreNlsCreditInfoVO preNlsCreditInfoVO, String glblSrlNo) throws ESBException {
        final NlsCreditApprovalInfoVO nlsCaaInfoVo = new NlsCreditApprovalInfoVO();
        //渠道预授信信
        nlsCaaInfoVo.setChannelApplyNo(psdCreditApplyReqBean.getChannelApplyNo());
        //企业注册地
        nlsCaaInfoVo.setRegistration(preNlsCreditInfoVO.getRegistration());
        //创建人
        nlsCaaInfoVo.setCreateUser(BaseConstant.ADMIN);
        //创建时间
        nlsCaaInfoVo.setCreateTime(new Date());
        //最后更新人
        nlsCaaInfoVo.setLastUpdateUser(BaseConstant.ADMIN);
        //最后更新时间
        nlsCaaInfoVo.setLastUpdateTime(new Date());
        //
        nlsCaaInfoVo.setGlobalSerno(glblSrlNo);
        //授信申请流水号
        nlsCaaInfoVo.setLmtApplySeq(psdCreditApplyReqBean.getCrdtAppFlowNo());
        // 用来记录调用回写税局调用次数 初始化为0
        nlsCaaInfoVo.setExcuteTime(0);
        final int insert = nlsCreditApprovalInfoService.insert(nlsCaaInfoVo);
        if (insert != 1) {
            logger.error("普税贷授信申请 授信申请流水号:【" + psdCreditApplyReqBean.getCrdtAppFlowNo() + "】 插入授信审批信息表出现异常!");
            throw new ESBException(EsbRetCodeStandard.SJCLYC.getValue(), "插入数据入授信审批信息表出现异常!");
        }
    }

    /**
     * 插入业务过程表
     *
     * @param psdCreditApplyReqBean
     * @throws ESBException
     */
    private void composeProcessBizVoInfoInsert(PsdCreditApplyReqBean psdCreditApplyReqBean, PreNlsCreditInfoVO preNlsCreditInfoVO) throws ESBException {
        // 插入网贷业务过程表 保证后续记录各插槽执行状态
        NlsProcessBizVO nlsProcessBizVo = new NlsProcessBizVO();
        // 来源授信申请接口【必输】 授信申请流水号
        nlsProcessBizVo.setApplySeq(psdCreditApplyReqBean.getCrdtAppFlowNo());
        // 来源授信申请接口【必输】 客户姓名
        nlsProcessBizVo.setCusName(preNlsCreditInfoVO.getCertName());
        // 来源授信申请接口【必输】 产品ID
        nlsProcessBizVo.setPrdId(psdCreditApplyReqBean.getProdCd());
        // 来源授信申请接口【必输】 产品编码与产品ID一样
        nlsProcessBizVo.setPrdCode(psdCreditApplyReqBean.getProdCd());
        // 来源授信申请接口【必输】 产品名称
        nlsProcessBizVo.setPrdName(psdCreditApplyReqBean.getLoanProdNm());
        // 默认赋值 挂起次数
        nlsProcessBizVo.setHangTimes(QueueTaskEnums.QueueHangTimesEnum.INITIALIZE.getTimes());
        // 默认赋值 队列任务状态
        nlsProcessBizVo.setQueueTaskState(QueueTaskEnums.QueueTaskStateEnum.EXECUTORY.getCode());
        // 创建日期
        nlsProcessBizVo.setCreateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        // 默认赋值信息
        setServerInsertDefaultProperty(nlsProcessBizVo);
        int result = nlsProcessBizService.insertNlsProcessBiz(nlsProcessBizVo);
        if (result != 1) {
            logger.error("普税贷授信申请 授信申请流水号:【" + psdCreditApplyReqBean.getCrdtAppFlowNo() + "】 插入数据入网贷业务过程表出现异常!");
            throw new ESBException(EsbRetCodeStandard.SJCLYC.getValue(), "插入数据入网贷业务过程表出现异常!");
        }
    }

    private <T> T setServerInsertDefaultProperty(BaseInfo baseInfo) {
        try {
            BeanUtils.setProperty(baseInfo, "createTime", TimeUtil.getCurrentDateTime());
            BeanUtils.setProperty(baseInfo, "lastUpdateTime", TimeUtil.getCurrentDateTime());
            BeanUtils.setProperty(baseInfo, "createUser", BaseConstant.ADMIN);
            BeanUtils.setProperty(baseInfo, "lastUpdateUser", BaseConstant.ADMIN);
            BeanUtils.setProperty(baseInfo, "legalOrgCode", "广州银行智慧中心");
        } catch (Exception e) {
            LoggerFactory.getLogger(this.getClass()).error("设置新增默认属性时出现异常!", e);
        }
        return (T) baseInfo;
    }

    private String transferAssureMeansMain(String code) {
        if ("A".equals(code)) return "20";
        if ("B".equals(code)) return "10";
        if ("C".equals(code)) return "30";
        if ("D".equals(code)) return "00";
        return code;

    }

    @ModelAttribute("esbReqServiceBean")
    public EsbReqServiceBean getReqEsbHeadBean(HttpServletRequest request) {
        logger.info("获取 ESB请求系统头和请求应用头对象!");
        EsbReqServiceBean esbReqServiceBean = (EsbReqServiceBean) request.getAttribute("esbReqServiceBean");
        return esbReqServiceBean;
    }

    @ModelAttribute("psdCreditApplyReqBean")
    public PsdCreditApplyReqBean getReqEsbBodyBean(HttpServletRequest request) {
        logger.info("获取 ESB请求体！");
        String esbReqBody = (String) request.getAttribute("esbReqBody");
        return JSONObject.parseObject(esbReqBody, PsdCreditApplyReqBean.class);
    }

}